#ifndef PDXCXX_UTILS_H
#define PDXCXX_UTILS_H

#include <functional>
#include <vector>

#include "clang/Frontend/CompilerInstance.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/AST/AST.h"
#include "clang/AST/ParentMap.h"

namespace pdxcxx
{
	class ClangParser
	{
		clang::CompilerInstance m_CompilerInstance;
		std::vector<std::unique_ptr<clang::Preprocessor> > _leakedPreprocessors;

		void prepareCompilerforFile(const char* szSourceCodeFilePath);
		void prepareDefaults();
	public:
		ClangParser();
		~ClangParser();

		std::unique_ptr<clang::ASTContext> getAndResetASTContext();
		std::unique_ptr<clang::ASTContext> parseAST(const char* szSourceCodeFilePath,
			clang::ast_matchers::MatchFinder* finder = nullptr);

		/*
		// Executes CodeGenAction and returns the pointer (caller should own and delete it)
		// Returns NULL on failure (in case of any compiler errors etc.)
		clang::CodeGenAction* emitLLVM(const char* szSourceCodeFilePath);
		*/

		clang::ASTContext& getASTContext() const { return m_CompilerInstance.getASTContext(); }
		clang::SourceManager& getSourceManager() const { return m_CompilerInstance.getSourceManager(); }
		clang::DiagnosticConsumer& getDiagnosticClient() const { return m_CompilerInstance.getDiagnosticClient(); }
	};

	struct MatchAdapter : public clang::ast_matchers::MatchFinder::MatchCallback
	{
		typedef clang::ast_matchers::MatchFinder::MatchResult Result;
	private:
		typedef std::function<void(const Result&)> MatchFunction;
		MatchFunction _matchFunction;
	public:
		MatchAdapter(const MatchFunction& matchFunction);
		void run(const Result& result);
	};

	std::string mangle(const clang::NamedDecl* decl);
	std::string mangle(const clang::NamedDecl* decl, clang::ASTContext* context);
	std::string mangle(const clang::NamedDecl* decl, clang::MangleContext* context);
} //namespace pdxcxx

#endif //PDXCXX_UTILS_H
